<?php
declare(strict_types=1);

namespace app\index\services;

use JetBrains\PhpStorm\Internal\ReturnTypeContract;
use lib\data\StoreComponents;
use lib\data\virtual\GoodsOrder;
use sys\services\JsonWebSocket;
use swoole\http\Request;
use sys\Log;

class CenterWebSocket {
    protected ?\lib\Merchant $merchant = null;
    protected ?\lib\User $user = null;
    protected JsonWebSocket $ws;
    protected int $mid;
    protected ?\lib\LoginTokens $login = null;
    protected string $ipaddr;

    public function __construct(\Swoole\Http\Request $request) {
        $this->ipaddr = $request->header['x-real-ip'] ?? $request->header['x-forwarded-for'] ?? $request->server['remote_addr'];
    }

    # WS连接进入事件
    public function afterConnected(Request $request, JsonWebSocket $ws) :bool {
        Log::write("worker_id: ". \app\index\BootStarup::$workerId." after Connected.", 'DEBUG');
        $sid = (int)$request->get['sid'];

        # 检查worker_id是否匹配
        if(\app\index\BootStarup::$workerId !== $sid){
            Log::write('worker_id not match!', 'ERROR');
            $ws->close();
            return false;
        }

        if(isset($request->get['token'])) {
            if(!$this->auth($request->get, $token, $user, $login)){
                Log::write('token not match!', 'ERROR');
                $ws->push(['_SEQ'=>0, 'done'=>true, 'success'=>false, 'message'=>'登录已失效!']);
                $ws->close();
                return false;
            }

            $this->mid = $user->mid;
            $this->merchant = $user->merchant;
            $this->merchant->addChannel($this->ws = $ws);
            $ws->push(['_SEQ'=>0,'success'=>true, 'done'=>true, 'message'=>'welcome!']);
            $login->setTimeout(false);
            $this->login = $login;
            return true;
        }
        return false;
    }

    # WS连接断开事件
    # 通常在这里做一些清理工作.
    public function afterClose() {
        if(null!==$this->merchant){
            $this->merchant->removeChannel($this->ws);
        }
        # 重新设置超时时间
        $this->login->setTimeout(true);
    }

    # 被动验证登录
    protected function auth(array $msg, &$token, &$user, &$login) :bool {
        if(null !== $this->login){
            $login = $this->login;
            $user = $login->user;
            $token = $login->token;
            return true;
        }

        $token = $msg['token'];
        $login = \lib\LoginTokens::get($token);
        if(null === $login){
            $db = new \sys\Db();
            if(null === ($tokenr = $db->table('el_token')->where([['token','=', $token], ['plat_id','=', 0]])->find())){
                echo "验证失败! Token 已失效!\n";
                return false;
            }

            echo "验证通过!\n";
            if(null ===  \lib\Merchant::get($tokenr['auth']['mid'])){
                \lib\Merchant::initMerchants([$tokenr['auth']['mid']]);
            }
            if(null === ($user = \lib\User::get($tokenr['auth']['id']))){
                echo "用户不存在!\n";
                return false;
            }
            $login = new \lib\LoginTokens($token, $user);
        }
        $user = $login->user;
        return true;
    }

    # WS消息事件
    public function onSync(array $data, \Closure $update, \Closure $done) {
        Log::console('onSync: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(isset($data['data'])){
            $ret = ['success'=>true];
            \lib\sync\Synchronize::Synchronize($this->mid, $data['data'], $this->ws);
            return $ret;
        }
        return ['success'=>false, 'message'=>'同步字段必须.'];
    }


    # 消息删除
    public function onMsgRemove(array $data, \Closure $update, \Closure $done) {
        Log::console('onMsgRemove: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'id'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\virtual\Messages::remove($this->mid, (int)$data['data']['id']);
    }

    # 消息标记已读
    public function onMsgReaded(array $data, \Closure $update, \Closure $done) {
        Log::console('onMsgRead: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'id'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\virtual\Messages::readed($this->mid, (int)$data['data']['id']);
    }
    
    # 删除商品
    public function onGoodsRemove(array $data, \Closure $update, \Closure $done) {
        Log::console('onGoodsRemove: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'id'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\Components::GoodsRemove($this->merchant, $user->id, (int)$data['data']['id']);
    }

    # 商品列表
    public function onComponents(array $data, \Closure $update, \Closure $done) {
        Log::console('onComponents: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'cat_id'=>'require|uinteger',
            'code'=>'require|uinteger',
            'limit'=>'require|uinteger',
            'page'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\Components::read();
    }

    # 商品分类顺序调整
    public function onMoveCategory(array $data, \Closure $update, \Closure $done) {
        Log::console('onMoveCategory: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'data'=>'require|intlist:2',
        ],__LINE__.':'.__FILE__)->check($data);
        if(!$check->pass()) return $check->jsonSerialize();
        return  \lib\data\Category::Move($this->mid, (int)$data['data'][0], (int)$data['data'][1]);
    }

    # 仓库顺序调整
    public function onMoveStore(array $data, \Closure $update, \Closure $done) {
        Log::console('onMoveStore: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'data'=>'require|intlist:2',
        ],__LINE__.':'.__FILE__)->check($data);
        if(!$check->pass()) return $check->jsonSerialize();
        return  \lib\data\Store::Move($this->mid, (int)$data['data'][0], (int)$data['data'][1]);
    }

    # 商品顺序调整
    public function onMoveGoods(array $data, \Closure $update, \Closure $done) {
        Log::console('onMoveGoods: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'data'=>'require|intlist:2',
        ],__LINE__.':'.__FILE__)->check($data);
        if(!$check->pass()) return $check->jsonSerialize();
        return  \lib\data\Components::Move($this->mid, (int)$data['data'][0], (int)$data['data'][1]);
    }

    # 可售状态修改
    public function onSetOnSale(array $data, \Closure $update, \Closure $done) {
        Log::console('onSetOnSale: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'store_id'=>'require|uinteger',
            'goods_id'=>'require|uinteger',
            'on_sale'=>'require|boolean',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();
        $data = $data['data'];
        return  \lib\data\StoreComponents::setOnSale($this->mid, (int)$data['store_id'], (int)$data['goods_id'], (bool)$data['on_sale']);
    }

    # 商品分类列表获取
    public function onCategory(array $data, \Closure $update, \Closure $done) {
        Log::console('onCategory: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        Log::write('getall 2 ....','DEBUG');
        return ['success'=>true, 'data'=>\lib\data\Category::getAll($this->mid)];
    }

    # 商品分类删除
    public function onRemoveCategory(array $data, \Closure $update, \Closure $done) {
        Log::console('onRemoveCategory: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'id'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $cate = \lib\data\Category::get((int)$data['data']['id']);
        if(null === $cate){
            return ['success'=>false, 'message'=>'分类不存在.'];
        }
        return $cate->destroy($this->mid);
    }

    # 商品分类修改|创建
    public function onSaveCategory(array $data, \Closure $update, \Closure $done) {
        Log::console('onSaveCategory: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'id'        => 'uinteger',
            'name'      => 'require|length:1,32',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\Category::save($this->mid, $data['data']);
    }

    # 仓库修改|创建
    public function onSaveStore(array $data, \Closure $update, \Closure $done) {
        Log::console('onSaveStore: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'id'    => 'uinteger',
            'name'  => 'require|length:1,64',
            'prop'  => 'require|uinteger|in:0,1',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\Store::save($this->mid, $data['data']);
    }

    # 仓库删除
    public function onRemoveStore(array $data, \Closure $update, \Closure $done) {
        Log::console('onRemoveStore: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'id'=>'require|uinteger',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        return \lib\data\Store::destroy($this->mid, (int)$data['data']['id']);
    }

    # 进货
    public function onPurchase(array $data, \Closure $update, \Closure $done) {
        Log::console('onPurchase: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)){
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'store_id'          => 'require|uinteger',  # 仓库ID
            'calc_mode'         => 'require|uinteger|in:0,1',   # 计算方式 0:按件 1:按个
            'settle_mode'       => 'require|uinteger|in:0,2',   # 结算方式 0:挂账 1:现金
            'realpay|金额'      => 'requireIf:1,2,3,4,5,6,7,8,9,10,settle_mode|unumber',           # 实付金额
            'in'                => 'require|boolean',   # 是否入库
            'amount'          => 'require|unumber',   # 应付金额
            'goods'             => 'require|list',      # 商品列表
            'goods.id'          => 'require|uinteger',  # 商品ID
            'goods.num'         => 'require|uinteger',  # 进货数量
            'goods.piece_price' => 'requireIf:0,calc_mode|unumber',   # 进货件单价
            'goods.pack_price'  => 'requireIf:1,calc_mode|unumber',   # 进货个单价
            'goods.pack_size'   => 'requireIf:1,calc_mode|unumber',   # 进货个单价
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();
        $data = $data['data'];
        if(!isset($data['realpay']) || is_null($data['realpay'])){
            $data['realpay'] = null;
        }else{
            $data['realpay'] = (float)$data['realpay'];
        }
        return \lib\data\StoreComponents::purchase(
            $this->mid, 
            $user->id,
            (int)$data['store_id'], 
            (int)$data['calc_mode'], 
            (int)$data['settle_mode'], 
            is_null($data['realpay']) ? null : (float)$data['realpay'], 
            (bool)$data['in'], 
            (float)$data['amount'], 
            $data['goods']
        );
    }

    # 上架下架商品(商品移库)
    public function onMoveToStore(array $data, \Closure $update, \Closure $done) {
        Log::console('onMoveGoodsToStore: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'source_id'          => 'require|uinteger',         # 仓库ID
            'target_id'         => 'require|uinteger',          # 目标仓库ID
            'document_type'     => 'require|uinteger|in:2,3',   # 单据类型 4:上架 5:下架
            'desc'              => 'length:0,200',              # 移库描述
            'goods'             => 'require|list',              # 商品列表
            'goods.id'          => 'require|uinteger',          # 商品ID
            'goods.num'         => 'require|uinteger',          # 移库数量
        ],__LINE__.':'.__FILE__)->check($data['data']);

        if(!$check->pass()) return $check->jsonSerialize();
        $data = $data['data'];

        return \lib\data\StoreComponents::moveStore(
            $this->mid, 
            $user->id,
            (int)$data['document_type'],
            (int)$data['source_id'], 
            (int)$data['target_id'], 
            $data['goods'],
            $data['desc']
        );
    }

    # 吧台销售
    public function onSale(array $data, \Closure $update, \Closure $done) {
        Log::console('onSale: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'settle_mode'       => 'require|uinteger|in:0, 3, 4, 5',              # 结算方式 0:挂账 3:现金 4: 线上交易(非现金) 5: 会员卡(网吧计费卡)
            'pay_mode'          => 'requireIf:4,5|uinteger|in:0, 1, 2',           # 付款方式 0: 无, 1: 付款码, 2: 展示二维码
            'auth_code'         => 'requireIf:1,pay_mode|length:1,64',            # 付款码
            'timeout'           => 'requireIf:1,2,pay_mode|uinteger|between:1, 120', # 二维码超时时间(秒)
            'scene'             => 'require|uinteger|in:1,2,3',                           # 场景值  0 无场景 1 吧台 2 客户端 3 小程序 4 美团 5 饿了么 6 抖音 ....
            'realpay|金额'      => 'require|unumber',                             # 实付金额
            'amount'            => 'require|unumber',                             # 应付金额
            'desc'              => 'length:0,200',                                # 销售备注
            'goods'             => 'require|list',                                # 商品列表
            'goods.store_id'    => 'require|uinteger',                            # 货架ID
            'goods.id'          => 'require|uinteger',                            # 商品ID
            'goods.num'         => 'require|uinteger',                            # 购买数量
            'goods.give'        => 'require|boolean',                             # 是否赠送
            'goods.sale_price'  => 'requireIf:0,calc_mode|unumber',               # 商品售价
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];

        if(GoodsOrder::SCENE_BAR != $data['scene'] && $data['settle_mode'] == GoodsOrder::SETTLE_MODE_CASH){
            return ['success'=>false, 'message'=>'非吧台结算方式不能使用现金结算.'];
        }

        if(!isset($data['auth_code']) || is_null($data['auth_code'])){
            $data['auth_code'] = null;
        }
        if(!isset($data['desc']) || is_null($data['desc'])){
            $data['desc'] = '';
        }


        return \lib\data\Store::SaleGoods(
            $this->mid,                     # 商户ID
            $user->id,                      # 销售员ID
            (int)$data['scene'],            # 场景值
            (int)$data['settle_mode'],      # 付款方式
            (int)$data['pay_mode'],         # 付款方式
            (int)$data['timeout'] ?? 0,     # 二维码超时时间
            $data['auth_code'],             # 付款码
            (float)$data['realpay'],        # 实付金额
            $data['goods'],                 # 商品列表
            $data['desc'],                  # 销售备注
            $this->ipaddr,                  # 客户端IP
            $update                         # 更新回调
        );
    }

    public function onRefund(array $data, \Closure $update, \Closure $done) {
        Log::console('onShiftExchange: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'order_id'          => 'require|uinteger',          # 要退货的订单ID
            'goods'             => 'list',            # 商品列表
            'goods.store_id'    => 'require|uinteger',          # 仓库ID
            'goods.goods_id'    => 'require|uinteger',          # 商品ID
            'goods.num'         => 'require|uinteger',          # 退货数量
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];

        return \lib\data\Store::refund(
            $this->mid, 
            $user->id,
            (int)$data['order_id'], 
            $data['goods'],
            $this->ipaddr
        );
    }

    # 吧台配货接口
    public function onBarDistri(array $data, \Closure $update, \Closure $done) {
        Log::console('onBarDistri: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        
        $check = validate([
            'order_id'          => 'require|uinteger',          # 订单ID
            'mode'              => 'require|uinteger|in:1,2',   # 配货模式 1: 库存不足的不处理, 2: 库存不足的部分退款
            'distri'            => 'require|list',              # 商品列表
            'distri.id'         => 'require|uinteger',          # 配货表ID
            'distri.num'        => 'require|uinteger',          # 配货数量
            'distri.store_id'   => 'require|uinteger',          # 仓库ID
        ], __LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];

        return \lib\data\Store::barDistri(
            $this->mid, 
            $user->id,
            (int)$data['order_id'],
            (int)$data['mode'],
            $data['distri'],
            $this->ipaddr
        );
    }

    public function onShiftExchange(array $data, \Closure $update, \Closure $done) {
        Log::console('onShiftExchange: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'uid'               => 'require|uinteger',                            # 接班人ID
            'keep_cash'         => 'require|unumber',                             # 钱箱预留金额
            'desc'              => 'length:0,200',                                # 交班备注
            'sales'             => 'list',                                        # 交班销售
            'sales.store_id'    => 'require|uinteger',                            # 商品ID
            'sales.goods_id'    => 'require|uinteger',                            # 购买数量
            'goods.sale_price'  => 'require|unumber',                             # 商品售价
        ],__LINE__.':'.__FILE__)->check($data['data']);

        if(!$check->pass()) return $check->jsonSerialize();

        $merchant = $this->merchant;
        $data = $data['data'];
        return $merchant->exchange(
            $user->id,                      # 操作员ID
            (int)$data['uid'],              # 接班人ID
            (float)$data['keep_cash'],      # 钱箱预留金额
            $data['sales'],                 # 销售列表
            $data['desc'],                  # 交班备注
            $this->ipaddr                  # 客户端IP
        );
    }

    # 盘点库存
    function onStoreCheck(array $data, \Closure $update, \Closure $done) {
        Log::console('onInventoryCheck: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }
        $check = validate([
            'desc'              => 'length:0,200',      # 盘点备注
            'goods'             => 'require|list',      # 商品列表
            'goods.id'          => 'require|uinteger',  # 商品ID
            'goods.store_id'    => 'require|uinteger',  # 商品ID
            'goods.num'         => 'require|integer',   # 盘点数量(传递相对值)
            'goods.price'       => 'require|number',    # 盘点盈亏金额
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];
        return \lib\data\Store::StoreCheck($this->merchant, $user->id, $data['goods'], $data['desc']);
    }

    # 取消付款
    public function onMicropayCancel(array $data, \Closure $update, \Closure $done) {
        Log::console('onPayCancel: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'code'        => 'require:length:10,90',            # 付款码
        ],__LINE__.':'.__FILE__)->check($data['data']);

        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];
        if(\lib\pay\PayBase::micropay_cancel($data['code'], $this->ipaddr)){
            return ['success'=>true];
        }
        return ['success'=>false, 'message'=>'取消失败.'];
    }

    # 取消付款
    public function onStaQrpayCancel(array $data, \Closure $update, \Closure $done) {
        Log::console('onStaQrpayCancel: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');

        $check = validate([
            'out_trade_no'        => 'require:length:10,90',            # 付款码
        ],__LINE__.':'.__FILE__)->check($data['data']);

        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];
        if(\lib\pay\PayBase::qrcodepay_cancel($data['out_trade_no'], $this->ipaddr)){
            return ['success'=>true];
        }
        return ['success'=>false, 'message'=>'取消失败.'];
    }

    # 取消付款
    public function onQrpayCancel(array $data, \Closure $update, \Closure $done) {
        Log::console('onPayCancel: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        if(!$this->auth($data, $token, $user, $login)) {
            return ['success'=>false,'message'=>'请重新登录.'];
        }

        $check = validate([
            'out_trade_no'        => 'require:length:10,90',            # 付款码
        ],__LINE__.':'.__FILE__)->check($data['data']);

        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];
        if(\lib\pay\PayBase::qrcodepay_cancel($data['out_trade_no'], $this->ipaddr)){
            return ['success'=>true];
        }
        return ['success'=>false, 'message'=>'取消失败.'];
    }

    # 工作站销售
    public function onStaBuy(array $data, \Closure $update, \Closure $done) {
        Log::console('onStaBuy: '.json_encode($data, JSON_UNESCAPED_UNICODE), 'DEBUG');
        $check = validate([
            'szIDNO'        => 'require|length:1,32',   # 收货人卡号
            'szName'        => 'require|length:1,32',   # 收货人姓名
            'szAddress'     => 'require|length:1,200',  # 收货人地址
            'desc'          => 'length:0,200',          # 销售备注
            'settle_mode'   => 'require|in:4,5',        # 付款方式 4: 线上交易(非现金) 5: 会员卡(网吧计费卡)
            'goods'         => 'list:1',
            'goods.id'      => 'require|uinteger',
            'goods.num'     => 'require|uinteger|min:1',
        ],__LINE__.':'.__FILE__)->check($data['data']);
        if(!$check->pass()) return $check->jsonSerialize();

        $data = $data['data'];

        return \lib\data\Store::SaleGoods(
            $this->mid,                     # 商户ID
            0,                              # 销售员ID
            GoodsOrder::SCENE_STA,          # 场景值 2 工作站
            (int)$data['settle_mode'],      # 付款方式 4,5 现金
            GoodsOrder::PAY_MODE_QRCODE,    # 付款方式 2 用户扫码方式付款。
            120,                            # 二维码超时时间
            null,                           # 付款码
            0,                              # 实付金额
            $data['goods'],                 # 商品列表
            $data['desc'] ?? '',            # 订单备注
            $this->ipaddr,                  # 客户端IP
            $update,                        # 更新回调
            $data['szIDNO'],                # 收货人卡号
            $data['szName'],                # 收货人姓名
            '',                             # 收货人电话
            $data['szAddress'],             # 收货人地址
        );
    }
}